package scenic;

import java.awt.Rectangle;

import scenic.geom.Affine2;

/**
 * This brush paints a gradient.
 */
public class Gradient extends Brush {
	public static final int LINEAR = 0;
	public static final int RADIAL = 1;
	public static final int SQUARE = 2;
	public static final int CONICAL = 3;
	
	private int type;
	private ColorFunction function;
	private Affine2 transform;
	private Image image;
	
	/**
	 * Constructs a gradient.
	 */
	public Gradient() {
		transform = Affine2.identity();
	}

	/**
	 * Gets the type of the gradient.
	 */
	public int getType() {
		return type;
	}

	/**
	 * Sets the type of the gradient. The type must be either LINEAR,
	 * SQUARE, RADIAL or CONICAL.
	 */
	public void setType(int type) {
		this.type = type;
		changed();
	}

	/**
	 * Gets the color function.
	 */
	public ColorFunction getFunction() {
		return function;
	}

	/**
	 * Sets the color function. The color function determines the color
	 * slide of the gradient.
	 */
	public void setFunction(ColorFunction function) {
		this.function = function;
		changed();
	}

	/**
	 * Gets the transformation of the pattern.
	 */
	public Affine2 getTransform() {
		return transform;
	}

	/**
	 * Sets the transformation of the pattern. The transformation
	 * is used to transform the gradient. The transformation
	 * is typically used to scale and rotate the gradient.
	 */
	public void setTransform(Affine2 transform) {
		this.transform = transform;
		changed();
	}

	void draw(DrawContext context, Affine2 transform, Rectangle visibleArea) {
		if(image == null)
			updateImage();

		Affine2 tm = Affine2.multiply(transform, this.transform);

		context.renderer.color(context.context, 1.0f, 1.0f, 1.0f, 1.0f);
		context.renderer.setTransform(context.context, tm);
		context.renderer.gradient(context.context, type, image.getId());
	}

	private void updateImage() {
		if(image == null) {
			image = new Image(2048, 1, Format.A8R8G8B8);
		}
		byte[] colors = new byte[2048 * 4];
		double min = function.min();
		double max = function.max();
		int j = 0;
		
		for(int i = 0; i < 2048; i++) {
			double x = min + (i / 2047.0) * (max - min);
			Color c = function.value(x);
			
			colors[j++] = (byte)(Color.clamp(c.blue) * 255);
			colors[j++] = (byte)(Color.clamp(c.green) * 255);
			colors[j++] = (byte)(Color.clamp(c.red) * 255);
			colors[j++] = (byte)(Color.clamp(c.alpha) * 255);
		}
		
		image.write(colors);		
	}	
}
